#include "stdafx.h"

FilesRenamer::FilesRenamer(HWND parent, const std::list<wstring> &filesList) 
	: FilerFrogElement(parent)
{
	for (list<wstring>::const_iterator iter=filesList.begin(); iter!=filesList.end(); iter++)
	{
		m_filesList.push_back(*iter);
	}
}

void getFilePath(const wstring& folder, const wstring& anchor, const wstring& ext, wstring& retVal )
{
	retVal = folder + L"\\" + anchor + L"." + ext;
	if (ext == L"")
		retVal = folder + L"\\" + anchor;
}

int FilesRenamer::RenameToTempNames()
{
	int failed = 0;

	for (list<wstring>::const_iterator iter=m_filesList.begin(); iter!=m_filesList.end(); iter++)
	{
		if (!PathFileExists((*iter).c_str()))
		{
			wcout << L"1. File doesn't exist: ";
			FilesRefactorUtils::PrintUTF16ToStream(*iter, true, wcout);
			failed++;
		}
		else
		{
			FileMachine fm(m_parent, *iter);
			wstring folder;
			fm.Folder(folder);
			WCHAR szTempName[MAX_PATH];
			UINT dwTempFile = GetTempFileName(folder.c_str(), // folder to create in
									  L"frgtmp",  // temp file name prefix 
									  0,            // create unique name 
									  szTempName);  // buffer for name

			if (dwTempFile == 0)
			{
				wcout << L"FilesRenamer::Rename: GetTempFileName failed!" << endl;
				return -1;
			}

			wstring tmp(szTempName);

			DeleteFileOperation dfo(m_parent, szTempName, false, true, false);
			if (!dfo.Execute())
			{
				wcout << L"FilesRenamer::Rename: DeleteFileOperation failed!" << endl;
				return -1;
			}

			RenameFileOperation rfo(m_parent, (*iter).c_str(), tmp.c_str(), false, true);
			if (!rfo.Execute())
			{
				wcout << L"FilesRenamer::Rename: RenameFileOperation failed!" << endl;
				return -1;
			}

			m_tmpNames.push_back(tmp);
			m_orgNames.push_back(*iter);
		}
	}

	return failed;
}

int FilesRenamer::PerformRename()
{
	int failed = 0;

	for(list<wstring>::const_iterator iter=m_tmpNames.begin(); iter!=m_tmpNames.end(); iter++)
	{
		wstring tmpl(m_newNames.front());
		RenameFileOperation rfo(m_parent, iter->c_str(), m_newNames.front().c_str(), false, true);
		if (!rfo.Execute())
		{
			RenameFileOperation rfo1(m_parent, iter->c_str(), m_orgNames.front().c_str(), false, true);
			rfo1.Execute();
			failed++;
			continue;
		}
		
		m_newNames.pop_front();
		m_orgNames.pop_front();
	}

	return failed;
}

void FilesRenamer::Rename(FRRESPONSE& res)
{
	// checking if some of the files are open and if yes exist!
	for(list<wstring>::const_iterator iter = m_filesList.begin(); iter != m_filesList.end(); iter++)
	{
		if (FilesRefactorUtils::checkFileOpen(*iter))
		{
			wcout << L"FilesRenamer::Rename: Some files are open!" << endl;
	
			//MessageBox(NULL, L"KSKSKSKSKSKSKSK", L"ASdasasd", MB_OK);
			FilesRefactorUtils::FillResponse(res, FAIL_FILE_OPEN, RENAME, L"Some of the files are open.\nCan't complete rename operation.", 0, m_filesList.size());
			return;
		}
	}



	int failed = RenameToTempNames();
	if (failed == -1)
	{
		wcout << L"FilesRenamer::Rename: Unexpected error!" << endl;
		FilesRefactorUtils::FillResponse(res, FAIL_UNEXPECTED_ERROR, RENAME, L"An unexpected error occured.", 0, 0);
		return;
	}

	int err = GenerateNewNames();
	if (err == -2)
	{
		wcout << L"FilesRenamer::Rename: User decided not to overwrite existing files. Operation failed!" << endl;
		for (list<wstring>::const_iterator iter=m_tmpNames.begin(); iter!=m_tmpNames.end(); iter++)
		{
			RenameFileOperation rfo(m_parent, iter->c_str(), m_orgNames.front().c_str(), false, true);
			rfo.Execute();

			m_orgNames.pop_front();
		}

		FilesRefactorUtils::FillResponse(res, FAIL_USER_DECIDED, RENAME, L"", 0, m_filesList.size());
		return;
	}
	if (err == -1)
	{
		wcout << L"FilesRenamer::Rename: Unexpected error!" << endl;
		FilesRefactorUtils::FillResponse(res, FAIL_UNEXPECTED_ERROR, RENAME, L"An unexpected error occured.", 0, 0);		
		return;
	}
	
	list<wstring> retNewnames = list<wstring>(m_newNames);
	failed += err;
	failed += PerformRename();
	
	if (failed>0)
	{
		WCHAR str[10];
		_itow_s(failed, str, 10, 10);
		wstring msg(str + wstring(L" files failed to rename."));

		FilesRefactorUtils::FillResponse(res, FAIL_SOME_FILES_FAILED, RENAME, msg.c_str(), (m_filesList.size() - failed), failed);
	}
	else
		FilesRefactorUtils::FillResponse(res, SUCCESS, RENAME, L"", m_filesList.size(), 0);

	//for (list<wstring>::const_iterator iter=m_tmpNames.begin(); iter!=m_tmpNames.end(); iter++)
	res.NewFiles = retNewnames;
}

int FilesRenamer::CheckBlackList(const list<wstring>& blackList, int fail)
{
	if (blackList.size()>0)
	{
		if (FilesRefactorUtils::FrogMessageBox(m_parent, 
			L"Some files already exist with some of the destination file names.\nDo you want to overwrite?!\n(The existing files will be sent to the recycle bin)", 
			L"Warning!", 
			MB_YESNO|MB_ICONWARNING) == IDYES)
		{
			for(list<wstring>::const_iterator iter=blackList.begin(); iter!=blackList.end(); iter++)
			{
				DeleteFileOperation dfo(m_parent, iter->c_str(), false, true, true);
				if (!dfo.Execute())
				{
					return -1;
				}
			}
		}
		else
		{
			return -2;
		}
	}

	return fail;
}

FilesRenamerFindReplace::FilesRenamerFindReplace(HWND parent, const std::list<wstring> &filesList, const wstring& search, const wstring& replace)
: FilesRenamer(parent, filesList), m_search(search), m_replace(replace)
{}

int FilesRenamerFindReplace::GenerateNewNames()
{
	list<wstring> blackList;
	for (list<wstring>::const_iterator iter=m_orgNames.begin(); iter!=m_orgNames.end(); iter++)
	{
		FileMachine fm(FilerFrogElement::m_parent, *iter);

		wstring ext;
		fm.Extension(ext);

		wstring fName;
		fm.NameNoExt(fName);
		size_t pos = fName.find(m_search);

		wstring path(*iter);
		if (pos != wstring::npos)
		{
			while (pos != wstring::npos)
			{
				fName.replace(pos, m_search.length(), m_replace);
				pos = fName.find(m_search, pos+(m_replace.size()));
			}
			
			wstring folder;
			fm.Folder(folder);

			getFilePath(folder, fName, ext, path);
		}
		else
		{
			wcout << L"FilesRenamerFindReplace::GenerateNewNames: Can't find the search criteria for : ";
			FilesRefactorUtils::PrintUTF16ToStream(*iter, true, wcout);
		}

		if (PathFileExists(path.c_str()))
		{
			blackList.push_back(path);
		}

		m_newNames.push_back(path);
	}
	
	return CheckBlackList(blackList, 0);
}

FilesRenamerAutonumbering::FilesRenamerAutonumbering(HWND parent, const std::list<wstring> &filesList, int start)
: FilesRenamer(parent, filesList), count(start)
{}

int FilesRenamerAutonumbering::GenerateNewNames()
{
	list<wstring> blackList;
	for (list<wstring>::const_iterator iter=m_orgNames.begin(); iter!=m_orgNames.end(); iter++)
	{
		FileMachine fm(m_parent, *iter);
		
		wstring ext;
		fm.Extension(ext);
		wstring folder;
		fm.Folder(folder);

		WCHAR countStr[8];
		_itow_s(count, countStr, 8, 10);

		wstring path;
		getFilePath(folder, countStr, ext, path);
		
		if (PathFileExists(path.c_str()))
		{
			blackList.push_back(path);
		}

		m_newNames.push_back(path);

		count++;
	}

	return CheckBlackList(blackList, 0);
}

FilesRenamerAlphabetize::FilesRenamerAlphabetize(HWND parent, const std::list<wstring> &filesList)
	: FilesRenamer(parent, filesList), m_char(65), FIRST_CHAR(65), LAST_CHAR(90), m_count(1)
{}

void FilesRenamerAlphabetize::advanceChar()
{
	if (m_char == LAST_CHAR)
	{
		m_count++;
		m_char = FIRST_CHAR;
	}
	else
	{
		m_char++;
	}
}

int FilesRenamerAlphabetize::GenerateNewNames()
{
	list<wstring> blackList;
	for (list<wstring>::const_iterator iter=m_orgNames.begin(); iter!=m_orgNames.end(); iter++)
	{
		FileMachine fm(m_parent, *iter);
		
		wstring ext;
		fm.Extension(ext);
		wstring folder;
		fm.Folder(folder);

		WCHAR* fName = new WCHAR[m_count+1];
		wmemset(fName, m_char, m_count);
		fName[m_count] = '\0';

		wstring path;
		getFilePath(folder, fName, ext, path);
		
		if (PathFileExists(path.c_str()))
		{
			blackList.push_back(path);
		}

		m_newNames.push_back(path);

		advanceChar();
		delete[] fName;
	}

	return CheckBlackList(blackList, 0);
}

FilesRenamerAppend::FilesRenamerAppend(HWND parent, const std::list<wstring> &filesList, const wstring& prefix, const wstring& postfix)
: FilesRenamer(parent, filesList), m_prefix(prefix), m_postfix(postfix)
{}

int FilesRenamerAppend::GenerateNewNames()
{
	list<wstring> blackList;
	for (list<wstring>::const_iterator iter=m_orgNames.begin(); iter!=m_orgNames.end(); iter++)
	{
		FileMachine fm(m_parent, *iter);
		
		wstring ext;
		fm.Extension(ext);
		wstring folder;
		fm.Folder(folder);
		wstring fName;
		fm.NameNoExt(fName);

		wstring newName(m_prefix + fName + m_postfix);

		wstring path;
		getFilePath(folder, newName, ext, path);


		if (PathFileExists(path.c_str()))
		{
			blackList.push_back(path);
		}

		m_newNames.push_back(path);
	}

	return CheckBlackList(blackList, 0);
}

FilesRenamerAlphabetizeAppend::FilesRenamerAlphabetizeAppend(HWND parent, const std::list<wstring> &filesList, const wstring& prefix, 
												  const wstring& postfix)
	: FilesRenamerAlphabetize(parent, filesList), m_prefix(prefix), m_postfix(postfix)
{}

int FilesRenamerAlphabetizeAppend::GenerateNewNames()
{
	list<wstring> blackList;
	for (list<wstring>::const_iterator iter=m_orgNames.begin(); iter!=m_orgNames.end(); iter++)
	{
		FileMachine fm(m_parent, *iter);
		
		wstring ext;
		fm.Extension(ext);
		wstring folder;
		fm.Folder(folder);

		WCHAR* fName = new WCHAR[m_count+1];
		wmemset(fName, m_char, m_count);
		fName[m_count] = '\0';

		wstring path;
		getFilePath(folder, m_prefix + fName + m_postfix, ext, path);

		if (PathFileExists(path.c_str()))
		{
			blackList.push_back(path);
		}

		m_newNames.push_back(path);

		advanceChar();
		delete[] fName;
	}

	return CheckBlackList(blackList, 0);
}

FilesRenamerAutonumberAppend::FilesRenamerAutonumberAppend(HWND parent, const std::list<wstring> &filesList, int start,
														   const wstring& prefix, const wstring& postfix)
	: FilesRenamerAutonumbering(parent, filesList, start), m_prefix(prefix), m_postfix(postfix)
{}

int FilesRenamerAutonumberAppend::GenerateNewNames()
{
	list<wstring> blackList;
	for (list<wstring>::const_iterator iter=m_orgNames.begin(); iter!=m_orgNames.end(); iter++)
	{
		FileMachine fm(m_parent, *iter);

		wstring ext;
		fm.Extension(ext);
		wstring folder;
		fm.Folder(folder);

		WCHAR countStr[8];
		_itow_s(count, countStr, 8, 10);

		wstring path;
		getFilePath(folder, m_prefix + countStr + m_postfix, ext, path);

		if (PathFileExists(path.c_str()))
		{
			blackList.push_back(path);
		}

		m_newNames.push_back(path);

		count++;
	}

	return CheckBlackList(blackList, 0);
}


FilesRenamerMakeSameName::FilesRenamerMakeSameName(HWND parent, const std::list<wstring> &filesList, const wstring& anchor)
	: FilesRenamer(parent, filesList), m_anchor(anchor)
{}

// anchor not in list
int FilesRenamerMakeSameName::GenerateNewNames()
{
	int fail = 0;
	list<wstring> blackList;
	FileMachine fm1(m_parent, wstring(m_anchor));
	wstring anchor;
	fm1.NameNoExt(anchor);
	for (list<wstring>::const_iterator iter=m_orgNames.begin(); iter!=m_orgNames.end(); iter++)
	{
		FileMachine fm(m_parent, wstring(*iter));

		wstring ext;
		fm.Extension(ext);
		wstring folder;
		fm.Folder(folder);
		
		wstring path;
		getFilePath(folder, anchor, ext, path);

		wstring tmpl(m_anchor);
		if (path == *iter)
		{
			m_newNames.push_back(*iter);
			continue;
		}
		if ((path == m_anchor) ||
			(FilesRefactorUtils::ExistsInList(path, m_newNames)) ||
			(FilesRefactorUtils::ExistsInList(path, m_orgNames)))
		{
			m_newNames.push_back(*iter);
			fail++;
			continue;
		}
		if (PathFileExists(path.c_str()))
		{
			blackList.push_back(path);
		}

		m_newNames.push_back(path);
	}

	return CheckBlackList(blackList, fail);
}

FilesRenamerTruncate::FilesRenamerTruncate(HWND parent, const std::list<wstring> &filesList, 
										   int numberOfChars, bool truncFromBegining, bool includeFileExtension)
	: FilesRenamer(parent, filesList), m_numberOfChars(numberOfChars), m_truncFromBegining(truncFromBegining), m_includeFileExtension(includeFileExtension)
{}

int FilesRenamerTruncate::GenerateNewNames()
{
	int fail = 0;
	list<wstring> blackList;
	for (list<wstring>::const_iterator iter=m_orgNames.begin(); iter!=m_orgNames.end(); iter++)
	{

		FileMachine fm(m_parent, *iter);
		wstring fileName;
		wstring resultName;
		if (m_includeFileExtension)
		{
			fm.NamePlusExt(fileName);
		}
		else
		{
			fm.NameNoExt(fileName);
		}
				
		if (fileName.length()<=m_numberOfChars) // skip iteration if length too short
		{
			m_newNames.push_back(*iter);
			fail++;
			continue;
		}

		if (m_truncFromBegining)
		{
			resultName = fileName.substr(m_numberOfChars, fileName.length()-m_numberOfChars);
		}
		else
		{
			resultName = fileName.substr(0, fileName.length()-m_numberOfChars);
		}

		if (!m_includeFileExtension)
		{
			wstring ext;
			fm.Extension(ext);

			if (ext != L"")
				resultName = resultName + L"." + ext;
		}

		wstring dir;
		fm.Folder(dir);

		wstring fullPath(dir + L"\\" + resultName);

		if (FilesRefactorUtils::ExistsInList(fullPath, m_newNames))
		{
			m_newNames.push_back(*iter);
			fail++;
			continue;
		}
		if (PathFileExists(fullPath.c_str()))
		{
			blackList.push_back(fullPath);
		}

		m_newNames.push_back(fullPath);
	}

	return CheckBlackList(blackList, fail);
}